home *** CD-ROM | disk | FTP | other *** search
/ TPUG - Toronto PET Users Group / TPUG Users Group CD / TPUG Users Group CD.iso / MSDOS / (m)aaj / LPTX.ASM < prev    next >
Assembly Source File  |  1985-05-31  |  28KB  |  1,036 lines

  1.  
  2.  
  3. title LPTx : Line Printer Output Capture Routine
  4. page    66,132
  5. ;-------------------------------------------------------------
  6. ;
  7. ;    MAIN PROGRAM    Version 3.0
  8. ;
  9. ;  (C)    Copyright 1985 by Mark DiVecchio, All Rights Reserved
  10. ;
  11. ; You may use and freely distribute this program for
  12. ; non-commercial applications.
  13. ;
  14. ; Mark C. DiVecchio
  15. ; 9067 Hillery Drive
  16. ; San Diego, CA 92126
  17. ; 619-566-6810
  18. ;-------------------------------------------------------------
  19. ; This program intercepts the BIOS interrupt 17, the line printer
  20. ; interrupt. It will redirect the output of LPT1, LPT2, or LPT3 to a disk
  21. ; file. All three redirects may be active at the same time.
  22. ;
  23. ; This version (3.0) is fully compatible with IBM's PRINT command and
  24. ; hopefully most other print spoolers. I changed the method by which
  25. ; LPTX determines if a resident copy of itself is already in memory.
  26. ;
  27. ; Calling sequence:
  28. ; lptx -1 -o <d:[pathname]filename>
  29. ;
  30. ; where -1 means redirect LPT1, -2 means redirect LPT2, -3 means redirect
  31. ;       LPT3
  32. ;       This option must appear first
  33. ;
  34. ;       -o means start the redirect to file speicfied. If rerouting
  35. ;          is already in progress for the selected line printer,
  36. ;       the old file will be closed first.
  37. ;       (If you do not specify -o but you do specify a line printer,
  38. ;       LPTx will use either the last file name that you gave when
  39. ;       you loaded LPTx or will use the file named LPTX1.LST which it
  40. ;       will create in the root directory 
  41. ;       on the default drive - where x is 1, 2, or 3.)
  42. ;
  43. ;       It is not necessary that you specify the complete path name
  44. ;       for the file. LPTx opens and closes the file each time that it
  45. ;       writes out a block. If you change directories, LPTx will 
  46. ;       be able to find the file because it save the complete path.
  47. ;
  48. ;    -c means close the file and send all furthur output directly to the
  49. ;       line printer.
  50. ;
  51. ; if neither option is specified, LPTx just displays the program status.
  52. ;
  53. ; note: -1, -2, and -3 are mutually exclusive
  54. ;       -o and -c are mutually exclusive
  55. ;
  56. ; examples:
  57. ;
  58. ; lptx                Displays the program status
  59. ;
  60. ; lptx ?            Displays a HELP screen
  61. ;
  62. ; lptx -1            routes LPT1 output to file named
  63. ;                LPTX1.LST on the default drive or the last
  64. ;                named file.
  65. ;
  66. ; lptx -o a:\able.xxx        routes LPT1 output to file named
  67. ;    or            a:\able.xxx. Any open redirection
  68. ; lptx a:\able.xxx        disk file for LPT1 is closed.
  69. ;
  70. ; lptx -2 b:xx.lst        routes LPT2 output to file named
  71. ;                XX.LST in the default directory
  72. ;                on drive B:. Any open redirection
  73. ;                disk file for LPT2 is closed.
  74. ;
  75. ; lptx -3 d:\ab\cd\file.lst    redirects LPT3 output to the file named
  76. ;                file.lst in the directory ab\cd on drive
  77. ;                d:.
  78. ;
  79. ; lptx -c            closes any disk files open for LPT1 and sends
  80. ;    or            the output back to the line printer
  81. ; lptx -1 -c            If no rerouting is taking place to LPT1,
  82. ;                this is    a NOP. LPT2 and LPT3 are not
  83. ;                affected.
  84. ;
  85. ; lptx -2 -c            closes any disk file open for LPT2 and
  86. ;                sends the output back to line printer.
  87. ;                if no rerouting is taking place to LPT2,
  88. ;                this is a NOP. LPT1 and LPT3 are not
  89. ;                affected.
  90. ;
  91. ; By rerouting LPT2 or LPT3 to a disk file, you can in effect have 2 or 3
  92. ; printers on your system. LPT1 can be your physical printer and you can
  93. ; have LPT2 output going to disk. When you redirect LPT2 or LPT3, LPT1 works
  94. ; normally.
  95. ;
  96. ; If you are rerouting to a diskette file, do not remove the diskette
  97. ; once the rerouting starts. I recommend rerouting to a hard disk or
  98. ; a RAM disk.
  99. ;
  100. ; If LPTx encounters any kind of error during the rerouting, it terminates
  101. ; operation and sends output back to the line printer. It does not display
  102. ; anything but beeps the speaker four times. This prevents your currently
  103. ; running program from possibly getting destroyed.
  104. ; An error on LPT1 redirect does not shut down LPT2 or LPT3 redirect.
  105. ;
  106. ; LPTx captures the int 17h interrupt vector. It may not operate correctly
  107. ; with other routines what also intercept that vector.
  108. ;
  109. ; Problems may occur with print spoolers which also take over the int 17h 
  110. ; vector. You can be sure that LPTX works correctly by running LPTX after
  111. ; you have run your print spooler. LPTX will be transparent to the print
  112. ; spooler but your print spooler may not be transparent to LPTX.
  113. ; LPTX works fine with IBM's PRINT command.
  114. ;
  115. ; LPTx also captures the int 24h critical error interrupt vector. This is
  116. ; done only for the period that LPTx is using the disk. This prevents
  117. ; the generation of funny error messages in the middle of other programs
  118. ; that you may be running. (LPTx justs beeps 4 times and clears itself
  119. ; out of way if a disk error occurs).
  120. ;
  121. ; This version of LPTx can redirect all three printers to three different
  122. ; files with all 3 active at the same time.
  123. ;
  124. ; LPTx uses about 7K of memory for the resident data buffers and 
  125. ; interrupt handler.
  126. ;
  127. ; My thanks to Don D. Worth of UCLA/OAC for his program named SPOOL.
  128. ; He included the concept of the saving the DOS stack when the interrupt
  129. ; routine called DOS on its own. I stole the idea for this program.
  130. ;
  131. ; If you modify or find any bugs in this program, I would appreciate
  132. ; it if you would drop me a line with the changes. Use the address
  133. ; above.
  134. ;
  135. if1
  136.     %out Pass 1
  137. else
  138.     %out Pass 2
  139. endif
  140. ;
  141. ;-----------------------------------------------------------------
  142. null        equ    0
  143. off        equ    0
  144. on        equ    1
  145. empty        equ    0
  146. cr        equ    13
  147. lf        equ    10
  148. dollar        equ    '$'
  149. colon        equ    ':'
  150. backslash    equ    '\'
  151. blank        equ    ' '
  152. dash        equ    '-'
  153. dos_call    equ    21h
  154. bufsize        equ    200H    ;size of DMA buffer
  155. display_output    equ    9    ;for DOS call
  156. def_drive    equ    19h
  157. create_file    equ    3Ch
  158. open_file    equ    3Dh
  159. close_file    equ    3Eh
  160. write_file    equ    40h
  161. delete_file    equ    41h
  162. lseek_file    equ    42h
  163. def_path    equ    47h
  164. find_file    equ    4Eh
  165. ;-----------------------------------------------------------------
  166. ;
  167. ; Macros
  168. display    macro    msg
  169.     mov    DX,offset msg
  170.     mov    AH,display_output
  171.     int    dos_call
  172.     endm
  173. ;
  174. ;-----------------------------------------------------------------
  175. ;
  176. p_block    struc
  177. ;
  178. ; data structure - these variables are used only in the
  179. ; memory resident copy of LPTx. BX is set to point to the offset of the
  180. ; allocation of this structure for the selected LPT
  181. ;
  182. active    db    off        ;1 = this LPTx is on, 0 = off
  183. handle    dw    null        ;handle of disk file used by this LPT
  184. ;
  185. ; space for redirection disk file name
  186. ;
  187. filen    db    'a:\lptx'
  188. ptr    db    blank
  189.     db    '.lst',null
  190.     db    '                          '
  191.     db    '                        '
  192. ;
  193. sp_left    dw    empty        ;bytes left in DMA buffer for this LPT
  194. buffer    db    bufsize dup(?)    ;data buffer for this LPT
  195. ;
  196. p_block    ends
  197. ;
  198. ;
  199. ;
  200. ;-----------------------------------------------------------------
  201. ;
  202. subttl    Main Code
  203. page
  204. %out Assembling CODE Segment
  205. cseg    segment para public 'CODE'
  206.     assume  CS:cseg,DS:nothing,SS:nothing
  207. ;
  208.     org    100h
  209. lptx:    jmp    l_start
  210. id    dw    03579h        ;unique ID for this program
  211. ;
  212. ; What follows is three allocations of the Structure p_block
  213. ; One for each line printer that we can support.
  214. ; With this, all three line printers have DMA buffers and flag
  215. ; variables.
  216. ; BX is used to point to the offset of the allocation currently in use
  217. ;
  218. ; Line printer 1
  219. lpt1    p_block    <,,,'1'>
  220. ;
  221. ; Line printer 2
  222. lpt2    p_block    <,,,'2'>
  223. ;
  224. ; Line printer 3
  225. lpt3    p_block    <,,,'3'>
  226. ;
  227. lptxe    db    7,7,7,7,dollar    ;ring bell four times
  228. crit_flag    db    0    ;set to one if critical error occured
  229. off_crit    dw    0    ;save old critical error address
  230. seg_crit    dw    0
  231. ;
  232. dosstk    db    0C80H dup(?)    ;place to save INT 21H's stack
  233. stksav    dd    0        ;caller's stack EA
  234.     db    64 dup('STACK   ')
  235. stk    equ    this byte
  236. ;-----------------------------------------------------------------
  237. ;
  238. ; Interrupt handler
  239. ;
  240. prt_int:
  241.     cmp    DX,0F0Fh    ;my flag to detect that LPTX is
  242.                 ;already loaded and alive.
  243.     jne    reg_call    ;This is a regular print call
  244.     jmp    ret_ack
  245. reg_call:            ; set up BX
  246.     push    BX
  247.     cmp    DX,0        ;lpt1?
  248.     jne    chk_lpt2    ;no
  249.     mov    BX,offset lpt1    ;offset to LPT1
  250.     jmp    short bx_set
  251. chk_lpt2:
  252.     cmp    DX,1        ;lpt2?
  253.     jne    chk_lpt3    ;no
  254.     mov    BX,offset lpt2    ;offset to LPT2
  255.     jmp    short bx_set
  256. chk_lpt3:
  257.     cmp    DX,2        ;lpt3?
  258.     jne    ill_ptr        ;no - bad printer number
  259.     mov    BX,offset lpt3    ;offset to LPT3
  260. bx_set:
  261.     cmp    CS:[BX].active,off    ;are we active?
  262.     je    sleep        ;no
  263.     cmp    AH,1        ;initialize call?
  264.     je    do_nix        ;yes    
  265.     cmp    AH,2        ;status call?
  266.     je    do_nix        ;yes
  267.     cmp    AH,0        ;print call?
  268.     jne    do_nix        ;no
  269.     jmp    prt_it        ;we are active
  270. do_nix:    mov    AH,90h        ;Ready Status
  271.     pop    BX
  272.     iret
  273. ;
  274. ill_ptr:mov    AH,0
  275.     pop    BX
  276.     iret            ;return with error status
  277. ;
  278. ret_ack:            ;return acknowledgement that I'm here
  279.     mov    DX,05555h
  280.     mov    AX,0AAAAh
  281.     push    CS        ;now set up ES to point to the resident
  282.     pop    ES        ; data area
  283.     iret
  284. ;
  285. sleep:    pop    BX        ;restore BX before we go to sleep
  286.     db    0EAh        ;jump immediate to next handler
  287. oldint    dd    0        ;address of old int 17 routine
  288. ;-----------------------------------------------------------------
  289. ;
  290. ; Start the print process
  291. ;
  292. prt_it:    push    AX
  293.     push    BX
  294.     push    CX
  295.     push    DX
  296.     push    DS
  297.     push    ES
  298.     push    SI
  299.     push    DI
  300.     push    BP
  301.                 ; DS is used as the segment register
  302.                 ; for all data during the interrupt
  303. ;
  304.     push    CS
  305.     pop    DS        ;set up DS
  306. ;
  307.     cli
  308.     mov    SI,SS
  309.     mov    word ptr stksav+2,SI    ;save caller's stack
  310.     mov    SI,SP
  311.     mov    word ptr stksav,SI
  312.     mov    SI,CS
  313.     mov    SS,SI            ;give me new bigger stack
  314.     mov    SI,offset stk
  315.     mov    SP,SI
  316.     sti
  317.  
  318.     call    prnt            ;print the character
  319. ;
  320.     cli
  321.     mov    SI,word ptr stksav
  322.     mov    SP,SI            ;restore caller's stack
  323.     mov    SI,word ptr stksav+2
  324.     mov    SS,SI
  325.     sti
  326. ;
  327.     pop    BP
  328.     pop    DI
  329.     pop    SI
  330.     pop    ES
  331.     pop    DS
  332.     pop    DX
  333.     pop    CX
  334.     pop    BX
  335.     pop    AX
  336.     jmp    do_nix
  337. ;-----------------------------------------------------------------
  338. ;
  339. ; Critical Error Handler
  340. ;
  341. crit_int:                ;got critical error
  342.     mov    CS:crit_flag,on        ; set flag
  343.     mov    AL,0            ;tells DOS to ignore the
  344.     iret                ;error
  345. ;-----------------------------------------------------------------
  346. ;
  347. ; Print a character in AL
  348. ;
  349. prnt    proc    near
  350.     cmp    DS:[BX].active,off
  351.     je    prtext            ;nothing there?
  352.     push    AX
  353.     cmp    DS:[BX].sp_left,bufsize    ;buffer full
  354.     jne    intadd            ;no
  355.     call    flush            ;yes, flush buffer
  356. intadd:    pop    AX
  357.     mov    DI,BX            ;offset of this printer's allocation
  358.     add    DI,offset buffer    ;add in offset of buffer
  359.     add    DI,DS:[BX].sp_left    ;add in current byte count
  360.     mov    DS:[DI],AL        ;stuff it
  361.     inc    DS:[BX].sp_left
  362. prtext:    ret                ;done
  363. prnt    endp
  364. ;
  365. ;    Flush print buffer to disk file
  366. ;
  367. flush    proc    near
  368.     cmp    DS:[BX].sp_left,empty    ;buffer non-empty?
  369.     jne    flush_buf        ;empty, skip it
  370.     ret                ;exit
  371. flush_buf:
  372.     mov    DS:[BX].sp_left,empty    ;else, reset it
  373. ;
  374.     push    ES
  375.     push    DS
  376. ;
  377. ;    Preserve a chunk of DOS 2.0 across int 21h
  378. ;    See PC Technical reference manual page D-7 for hint.
  379. ;    It comments that only DOS calls 0 - 12 can be safely made
  380. ;    from an interrupt handler. "Use of any other call will
  381. ;    destroy the DOS stack and will leave DOS in an 
  382. ;    unpredictable state." What we do here is save and restore
  383. ;    3200 bytes of the DOS stack and restore it later. We only
  384. ;    do it for the DOS stack. If this was invoked by a user
  385. ;    program, we won't save the DOS stack or the user stack.
  386. ;    It is not necessary.
  387. ;
  388.     mov    AX,word ptr DS:stksav+2    ;get callers stack segment
  389.     cmp    AX,0100h        ; is it DOS?
  390.     ja    flusha            ;no, don;t bother to save it
  391.     mov    AX,DS            ;copy to my segment
  392.     mov    ES,AX
  393.     mov    AX,word ptr DS:stksav+2    ;copying from caller's stack
  394.     mov    DS,AX
  395.     mov    SI,0            ;offset into DOS's stack
  396.     mov    DI,offset dosstk
  397.     mov    CX,0C80h        ;length to save
  398.     cld
  399.     rep    movsb            ;copy DOS's stack
  400. ;
  401.     pop    DS
  402.     push    DS
  403. ;
  404. flusha:
  405. ;
  406.     push    AX            ;save the character
  407.     push    BX
  408.     push    ES
  409.     mov    AX,3524h        ;get old critical error vector
  410.     int    dos_call
  411.     mov    DS:off_crit,BX
  412.     mov    DS:seg_crit,ES
  413.     mov    DX,offset crit_int
  414.     mov    AX,2524h    
  415.     int    dos_call            ;trap critical error vector
  416.     mov    DS:crit_flag,off        ;clear critical error flag
  417.     pop    ES
  418.     pop    BX
  419.     pop    AX
  420. ;                    open file
  421.     mov    DX,BX
  422.     add    DX,offset filen        ;filename
  423.     mov    AL,1            ;open for writing
  424.     mov    AH,open_file
  425.     int    dos_call
  426.     mov    DS:[BX].handle,AX    ;file handle
  427.     jc    flush_err        ;error
  428.     cmp    DS:crit_flag,on        ;critical error?
  429.     je    flush_err        ;yes
  430. ;
  431.     push    BX
  432.     mov    AH,lseek_file
  433.     mov    AL,2            ;end of file
  434.     mov    CX,0            ;offset 0
  435.     mov    DX,0
  436.     mov    BX,DS:[BX].handle
  437.     int    dos_call
  438.     pop    BX
  439.     jc    flush_err        ;some seek error
  440.     cmp    DS:crit_flag,on        ;critical error?
  441.     je    flush_err        ;yes
  442. ;
  443.     mov    CX,bufsize        ;buffer length
  444.     mov    DX,BX            ;offset of structure allocation
  445.     add    DX,offset buffer    ;add offset of buffer within the
  446.                     ;    allocation
  447.     push    BX
  448.     mov    AH,write_file
  449.     mov    BX,DS:[BX].handle    ;file handle
  450.     int    dos_call        ;buffer address is DS:DX
  451.     pop    BX
  452.     jnc    flush_ok
  453.     cmp    DS:crit_flag,on        ;critical error?
  454.     je    flush_err        ;yes
  455.     cmp    AX,bufsize        ;did DOS write it all?
  456.     je    flush_ok        ;yes
  457. ;
  458. flush_err:
  459.     display lptxe            ;ring bell
  460.     mov    DS:[BX].active,off    ;turn us off
  461.     mov    DS:crit_flag,off    ;clear error flag
  462. ;                    ;then try to close the file
  463. ;                    ;to save what we can
  464. flush_ok:
  465.     push    BX
  466.     mov    BX,DS:[BX].handle
  467.     mov    AH,close_file        ;close the file
  468.     int    dos_call
  469.     pop    BX
  470. ;
  471. flush_exit:
  472.     pop    DS
  473.     pop    ES
  474. ;
  475.     push    DS
  476.     lds    DX,dword ptr DS:off_crit
  477.     mov    AX,2524h        ;restore critical error vector
  478.     int    dos_call
  479.     pop    DS
  480. ;
  481.     mov    AX,word ptr DS:stksav+2    ;copying to DOS's workarea
  482.     cmp    AX,100H
  483.     ja    flushe            ;must be DOS's segment
  484.     push    ES
  485.     mov    ES,AX
  486.     mov    DI,0            ;restore data areas
  487.     mov    SI,offset dosstk
  488.     mov    CX,0C80H        ;length to restore
  489.     cld
  490.     rep    movsb            ;copy DOS's stack
  491.     pop    ES            ;restore ES
  492. ;
  493. flushe:    ret
  494. flush    endp
  495. ;
  496. end_res    db    0
  497. ;
  498. ;
  499. ; This is the end of the memory resident portion of LPTx
  500. ;
  501. ;
  502. ;--------------------------------------------------------------------
  503. ;--------------------------------------------------------------------
  504. ;--------------------------------------------------------------------
  505. ;
  506. ; all following data is in the Code Segment
  507. ;
  508. mach_type    db    0
  509. save_psp    dw    0
  510. DOS_version    db    0        ;Major Version Number
  511.         db    0        ;Minor Version Number
  512. drive        db    0        ;default drive number 0=A etc.
  513. flag_27        db    0        ; 1=make this copy resident
  514. wrong_dos    db    'DOS 2.0 or later required for LPTx',lf,cr,dollar
  515.  
  516. up_msg        db    'LPTx - Line Printer Redirection Program - V3.00'
  517.         db    lf,cr,'   Copyright 1985 Mark C. DiVecchio',lf,cr
  518.         db    dollar
  519. resident    db    lf,cr,'Resident Portion of LPTx Loaded',lf,lf,cr
  520.         db    dollar
  521. lptx_err_3    db    'Could not delete file',lf,cr,dollar
  522. lptx_over    db    cr,lf,'File already exists. Do you want to overwrite '
  523.         db    'it? (y or n)  :$'
  524. lptx_nc        db    'File selection canceled',cr,lf,dollar
  525. lptx_del    db    'File is being overwritten',lf,cr,dollar
  526. lptx_cr        db    lf,cr,dollar
  527. lptx_bad    db    'Invalid Option',lf,cr
  528.         db    'Calling sequence:',lf,cr
  529.         db    'lptx {-1,-2,-3} {-c -o <d:[pathname]filename>}'
  530.         db    lf,cr,dollar
  531. lptx_on        db    lf,cr,'Redirection started. Disk file opened.'
  532.         db    lf,cr,dollar
  533. lptx_off    db    lf,cr,'Redirection ended. Disk file closed.'
  534.         db    lf,cr,dollar
  535. lptx_creat    db    'Could not create the disk file',lf,cr,dollar
  536. ;
  537. ; HELP screen
  538. ;
  539. help_msg    db    lf,cr,'Calling sequence : ',lf,lf,cr
  540.         db    'LPTX -p -f <[d:][\pathname\pathname]filename>'
  541.         db    lf,lf,cr
  542.         db    '    where  p = printer number : 1, 2, or 3',lf,cr
  543.         db    '           f = function : o for open a print file'
  544.         db    lf,cr
  545.         db    '                          c for close a print file'
  546.         db    lf,cr
  547.         db    '           drive letter & pathname are optional'
  548.         db    lf,cr
  549.         db    '    defaults : p = 1',lf,cr
  550.         db    '               f = o',lf,cr,dollar
  551. ;
  552. ; messages for STAT proc
  553. ;
  554. stat_stat    db    cr,lf,'LPTx Status :',cr,lf,dollar
  555. stat_lp        db    'lpt'
  556. stat_ptr    db    ' : $'
  557. stat_off    db    ' not redirected',cr,lf,dollar
  558. stat_dir    db    ' redirected to disk file '
  559. stat_fn        db    60 dup (blank)
  560. ;
  561. ;
  562. yn_max        db    2    ;max # of char
  563. yn_act        db    0
  564. yn_in        db    2 dup (0)
  565. ;
  566. ;--------------------------------------------------------------------
  567. ;
  568. ; This is the main routine which is executed each time that LPTx is 
  569. ; called. In this routine, DS points to the data segment which is
  570. ; transient. ES points to the data segment which is permanently
  571. ; resident. ES:BX points to the data structure for the selected 
  572. ; line printer, 1, 2, or 3.
  573. ; The offsets are the same for both. If this is the first
  574. ; time that LPTx is run, then ES=DS.
  575. ;
  576. l_start:
  577.     sti        ;interrupts on
  578.     push    DS    ;Save DS
  579.     xor    AX,AX    ;clear AX for return IP
  580.     push    AX    ;put 0 on stack
  581. ;
  582. ;to check for machine type look at
  583. ; F000:FFFE
  584. ;    = FF    IBM PC
  585. ;    = FE    IBM XT
  586. ;    = FD    IBM PCjr
  587. ;    = FC    IBM PC AT
  588. ;
  589.     mov    AX,0F000h
  590.     mov    ES,AX
  591.     mov    BX,0FFFEh
  592.     mov    CL,ES:[BX]    ;get machine type
  593.     mov    mach_type,CL    ;save machine type
  594.     mov    save_psp,DS    ;segment address of PSP
  595. ;
  596. ; get the DOS version number
  597. ; returns zero for pre DOS 2.0 releases
  598.     mov    AH,30h
  599.     int    dos_call    ;call DOS
  600.     mov    word ptr DOS_version,AX    
  601. ;
  602.     cmp    DOS_version,2    ;is it DOS 2.+
  603.     jge    dos_ok        ;yes
  604.     display    wrong_dos    ;print error message
  605.     mov    AH,0
  606.     int    dos_call    ;terminate
  607. dos_ok:
  608. ;
  609.     mov    AH,def_drive    ;get current default drive
  610.     int    dos_call
  611.     mov    drive,AL    ;save the drive number
  612.     display    up_msg        ;print program ID
  613. ;
  614. ; get old interrupt handler
  615. ;
  616.     mov    flag_27,off    ;to not make resident
  617.     mov    AL,17h        ;get current vector address
  618.     mov    AH,35h
  619.     int    dos_call
  620.     mov    word ptr oldint,BX
  621.     mov    word ptr oldint[2],ES    ;save it for later use
  622. ;
  623. ; are we already resident in memory?
  624. ;
  625.     mov    DX,0F0Fh        ;check if LPTX is already resident
  626.     mov    AX,2            ;get status
  627.     int    17h            ;call int 17h - BIOS
  628.     cmp    DX,5555h        ;my handler sets DX to 5555h
  629.                     ;and sets ES 
  630.     je    in_core            ;yes - ES has segment address
  631.     mov    flag_27,on        ;to make this copy resident
  632.     push    CS
  633.     pop    ES            ;set ES to CS for segment address
  634. ;
  635.     mov    AL,drive
  636.     add    AL,'a'            ;make it a letter
  637.     mov    BX,offset lpt1
  638.     mov    ES:[BX].filen,AL    ;put it into the filename
  639.     mov    BX,offset lpt2
  640.     mov    ES:[BX].filen,AL    ;put it into the filename
  641.     mov    BX,offset lpt3
  642.     mov    ES:[BX].filen,AL    ;put it into the filename
  643. in_core:                ;ES is ok
  644. ; ----------------------------------------------------
  645. ; ES now points to resident data area
  646. ;
  647. ; set up ES:BX to point to default data structure
  648. ;
  649.     mov    BX,offset lpt1        ;offset - default to LPT1
  650. ;
  651. ;get options and file name
  652. ;scan input line for line printer number
  653. ;
  654.     mov    SI,81h            ;starting offset
  655.     mov    CL,DS:80h        ;length of input line
  656.     mov    CH,0
  657.     cmp    CX,0            ;nothing?
  658.     jne    inp_lp            ;no
  659.     jmp    nor_exit        ;yes, then just display status
  660. inp_lp:
  661.     cmp    byte ptr DS:[SI],'?'    ;a ?  ?
  662.     jne    cont_scan        ;no
  663.     jmp    help            ;yes - go show help data
  664. cont_scan:
  665.     cmp    byte ptr DS:[SI],dash    ;a dash ?
  666.     je    got_opt            ;yes
  667.     cmp    byte ptr DS:[SI],cr    ;a carriage return?
  668.     je    scan_done        ;yes
  669.     cmp    byte ptr DS:[SI],blank    ;a blank?
  670.     je    inp_ret            ;yes
  671.     jmp    no_b            ;assume that we got a file name
  672.                     ;without the -o option
  673. inp_ret:
  674.     inc    SI            ;ignore blanks
  675.     loop    inp_lp            ;continue to scan
  676. ;
  677. ; scan of whole line is complete, if options were not found, we
  678. ; use defaults : LPT1 and file LPTX1.LST on the default drive.
  679. ; note : at least one option must be specified
  680. ;
  681. scan_done:
  682.     jmp    lptx_make        ;go create the file
  683. ;
  684. got_opt:                ;we got an option
  685.     inc    SI            ;to option
  686.     cmp    byte ptr DS:[SI],'1'    ;LPT1?
  687.     jne    chk_2
  688.     mov    BX,offset lpt1        ;offset from ES
  689.     jmp    short inp_ret
  690. chk_2:    cmp    byte ptr DS:[SI],'2'    ;LPT2?
  691.     jne    chk_3
  692.     mov    BX,offset lpt2        ;offset from ES
  693.     jmp    short inp_ret
  694. chk_3:    cmp    byte ptr DS:[SI],'3'    ;LPT3?
  695.     jne    chk_fil
  696.     mov    BX,offset lpt3        ;offset from ES
  697.     jmp    short inp_ret
  698. chk_fil:                ;is it file?
  699.     cmp    byte ptr DS:[SI],'o'    ;open a file
  700.     je    file_op            ;yes
  701.     cmp    byte ptr DS:[SI],'c'    ;close a file
  702.     je    file_cl            ;yes
  703.     display    lptx_bad        ;incorrect option
  704.     jmp    nor_ex
  705. ;
  706. file_cl:                ;close the output file
  707.     cmp    ES:[BX].active,on    ;are we active?
  708.     jne    no_close        ;no
  709.     mov    AL,1AH            ;CTRL-Z
  710.     mov    word ptr ES:stksav+2,AX    ;do this so that prnt does
  711.                     ;not bother to save the DOS stack
  712.     push    DS
  713.     push    ES
  714.     pop    DS            ;set DS to point to resident
  715.                     ;data segment
  716.     call    prnt            ;print end of file mark
  717.     call    flush            ;flush out write buffer
  718.     pop    DS            ;restore DS
  719. ;
  720.     mov    ES:[BX].active,off    ;make us inactive
  721.     display lptx_off        ;redirection off message
  722. no_close:
  723.     jmp    nor_exit        ;nothing to close so exit
  724. file_op:                ;open a file for output
  725. ;get the file name
  726.     inc    SI            ;to next chracter
  727.     cmp    byte ptr DS:[SI],blank    ;a blank?
  728.     jne    no_b            ;no
  729.     inc    SI            ;skip over blank
  730. no_b:
  731. ; at this point, we have found a new file name. We close the old
  732. ; file if one was open
  733.     cmp    ES:[BX].active,on    ;are we active?
  734.     jne    no_cl            ;no
  735.     mov    AL,1AH            ;CTRL-Z
  736.     mov    word ptr ES:stksav+2,AX    ;do this so that prnt does
  737.                     ;not bother to save the DOS stack
  738.     push    DS
  739.     push    ES
  740.     pop    DS            ;set DS to point to resident
  741.                     ;data segment
  742.     call    prnt            ;print end of file mark
  743.     call    flush            ;flush out write buffer
  744.     pop    DS            ;restore DS
  745. ;
  746.     mov    ES:[BX].active,off    ;make us inactive
  747.     display lptx_off        ;redirection off message
  748. no_cl:
  749.     mov    DI,BX            ;base of structure
  750.     add    DI,offset filen        ;add offset of destination
  751. ;
  752.     push    SI            ;save pointer to file name
  753. ; search for a drive letter
  754.     inc    SI            ;should point to a colon if
  755.                     ;one is there
  756.     cmp    byte ptr [SI],colon    ;?
  757.     je    got_drive        ;yes
  758. get_drive:
  759.     mov    AL,drive        ;get drive letter
  760.     add    AL,'a'            ;make it a letter
  761.     mov    ES:[DI],AL        ;put it in file name
  762.     inc    DI
  763.     mov    byte ptr ES:[DI],colon    ;put in a colon
  764.     inc    DI
  765.     jmp    path_search
  766. got_drive:
  767.     pop    SI            ;move pointer back to start
  768.     mov    AL,[SI]            ;get the given drive
  769.     mov    ES:[DI],AL        ;move it
  770.     sub    AL,'a'            ;make it a number
  771.     mov    drive,AL        ;save the drive number
  772.     inc    SI
  773.     inc    DI
  774.     mov    byte ptr ES:[DI],colon
  775.     inc    DI
  776.     inc    SI
  777.     push    SI            ;save new start pointer
  778. path_search:
  779. ; now search for a backslash which says that a pathname was given
  780. bk_s_lp:cmp    byte ptr [SI],backslash
  781.     je    got_path        ;a path
  782.     cmp    byte ptr [SI],cr    ;end of the file name?
  783.     je    get_path        ;yes with no path
  784.     inc    SI
  785.     jmp    short bk_s_lp            ;loop
  786. get_path:
  787.     mov    byte ptr ES:[DI],backslash    ;create the path
  788.     inc    DI
  789.     mov    DL,drive        ;the current drive
  790.     inc    DL            ;bump it for DOS
  791.     push    DS
  792.     push    ES
  793.     pop    DS            ;set up DS for DOS
  794.     mov    SI,DI            ;set up SI for pathname
  795.     mov    AH,def_path        ;get current directory
  796.     int    dos_call        ;path goes into DS:SI
  797.     pop    DS            ;restore DS
  798.     cmp    byte ptr ES:[SI],null    ;null path?
  799.     je    null_path        ;yes - root directory
  800. path_lp:                ;now find the end of the string
  801.     cmp    byte ptr ES:[SI],null    ;null byte marks end of pathname
  802.     je    end_path        ;now append the file name
  803.     inc    SI
  804.     jmp    short path_lp
  805. end_path:
  806.     mov    byte ptr ES:[SI],backslash
  807.     inc    SI
  808. null_path:
  809.     mov    DI,SI            ;DI is destination
  810. got_path:
  811.     pop    SI            ;restore source of filename
  812. ; pick up everything to next blank
  813. get_lp:
  814.     mov    AL,DS:[SI]        ;character
  815.     mov    ES:[DI],AL        ;put it away
  816.     cmp    AL,cr            ;was it a Carriage Return?
  817.     je    end_line
  818.     cmp    AL,blank        ;was it a space?
  819.     je    end_line
  820.     inc    SI
  821.     inc    DI
  822.     jmp    short get_lp        ;no so get next character
  823. end_line:
  824.     mov    byte ptr ES:[DI],null    ;zero out the CR or blank
  825.                     ;at the end of the filename
  826.                     ;it becomes an ASCIIZ string
  827.     sub    DI,BX            ;now take out the base and
  828.     cmp    DI,offset filen        ; make sure that we got something
  829.     jne    lptx_make        ;file name was ok
  830.     display lptx_creat        ;could not understand the file name
  831.     jmp    nor_exit        ;don't stay resident
  832. ;
  833. nor_ex:    jmp    nor_exit
  834.  
  835. lptx_make:
  836. ;
  837. ; default DTA used by Find File is set by DOS to an offset of
  838. ; 80h into this program's Program Segment Prefix
  839. ;
  840.     push    DS
  841.     push    ES
  842.     pop    DS            ;uses DS:DX
  843.     mov    DX,BX
  844.     add    DX,offset filen        ;file name
  845.     mov    AH,find_file
  846.     mov    CX,0            ;normal files only
  847.     int    dos_call        ;find first match
  848.     pop    DS
  849.     jnc    lptx_d            ;file was found
  850.     jmp    lptx_create        ;not there - which is ok
  851. ;file already exists
  852. lptx_d:    display lptx_over
  853.     mov    DX,offset yn_max;input buffer
  854.     mov    AH,0AH
  855.     int    dos_call
  856.     cmp    yn_act,0        ;anything typed?
  857.     display    lptx_cr
  858.     je    lptx_x            ;no - exit
  859.     cmp    yn_in,'y'        ;a yes?
  860.     je    lptx_d_yes        ;yes
  861.     cmp    yn_in,'Y'        ;a yes?
  862.     je    lptx_d_yes        ;yes
  863. lptx_x:    display    lptx_nc
  864.     jmp    nor_exit    ;all done if we can't overwrite
  865.                 ;see if we should abort the host
  866. lptx_d_yes:
  867.     display lptx_del
  868. ;
  869.     push    DS
  870.     push    ES
  871.     pop    DS            ;uses DS:DX
  872.     mov    DX,BX
  873.     add    DX,offset filen        ;file name
  874.     mov    AH,delete_file
  875.     int    dos_call        ;delete file
  876.     pop    DS
  877.     jnc    lptx_create        ;ok its gone
  878.     display lptx_err_3        ;can't delete it
  879.     jmp    nor_exit
  880. ;
  881. ;
  882. lptx_create:
  883. ;
  884. ; create the file
  885.     push    DS
  886.     push    ES
  887.     pop    DS            ;uses DS:DX
  888.     mov    DX,BX            ;base of this LPT's structure
  889.     add    DX,offset filen        ;file name
  890.     mov    AH,create_file
  891.     mov    CX,0            ;normal files only
  892.     int    dos_call            ;find first match
  893.     pop    DS
  894.     jnc    creat_ok
  895.     display lptx_creat        ;could not create the file
  896.     jmp    nor_exit        ;don't stay resident
  897. ;
  898. creat_ok:                ;now close the file
  899.     push    BX
  900.     mov    BX,AX            ;AX was loaded by the create file
  901.                     ;    call
  902.     mov    AH,close_file        ;close the file
  903.     int    dos_call
  904.     pop    BX
  905. ;
  906.     display    lptx_on
  907. ; set the program up for writing
  908.     mov    ES:[BX].sp_left,empty    ;set buffer empty
  909.     mov    ES:[BX].active,on    ;set us on
  910. ;
  911.     cmp    flag_27,on        ;make this one resident?
  912.     jne    nor_exit        ;no
  913. ;
  914. ; Now set LPTX up as the new int 17h interrupt handler
  915. ;
  916.     mov    AH,25h            ;set interrupt vector
  917.     mov    AL,17h            ;BIOS printer
  918.     mov    DX,offset prt_int
  919.     int    dos_call
  920.     display resident        ;resident loaded message
  921.     call    stat            ;display status
  922.     mov    DX,offset end_res
  923.     int    27h            ;terminate but stay resident
  924. ;
  925. ; HELP printer
  926. ;
  927. help:    display    help_msg        ;display the HELP screen
  928.     jmp    short nor_exit
  929. ;
  930. ; Normal exit for transient copy of LPTX
  931. ;
  932. nor_exit:
  933.     call    stat            ;display status
  934.     mov    AH,0
  935.     int    dos_call        ;terminate
  936. ;----------------
  937. ;
  938. ; displays the status of each of the three line printers
  939. ;
  940. stat    proc    near
  941. ; display each LPTx with a message "not redirected"
  942. ;            or redirected to <filename>
  943.     display    stat_stat
  944. stat_1:
  945.     mov    BX,offset lpt1        ;first printer
  946.     mov    stat_ptr,'1'
  947.     display    stat_lp
  948.     cmp    ES:[BX].active,on    ;are we active?
  949.     je    stat_1_a        ;yes
  950.     display stat_off
  951.     jmp    short stat_2
  952. stat_1_a:
  953.     mov    SI,BX            ;base
  954.     add    SI,offset filen        ;offset
  955.     mov    DI,offset stat_fn
  956. stat_1_lp:
  957.     mov    AL,ES:[SI]
  958.     mov    [DI],AL
  959.     inc    SI
  960.     inc    DI
  961.     cmp    AL,null            ;loop till a null byte is found
  962.     jne    stat_1_lp
  963.     mov    byte ptr [DI],cr
  964.     inc    DI
  965.     mov    byte ptr [DI],lf
  966.     inc    DI
  967.     mov    byte ptr [DI],dollar
  968.     display stat_dir        ;display file name
  969. ;
  970. stat_2:
  971.     mov    BX,offset lpt2        ;second printer
  972.     mov    stat_ptr,'2'
  973.     display    stat_lp
  974.     cmp    ES:[BX].active,on    ;are we active?
  975.     je    stat_2_a        ;yes
  976.     display stat_off
  977.     jmp    short stat_3
  978. stat_2_a:
  979.     mov    SI,BX            ;base
  980.     add    SI,offset filen        ;offset
  981.     mov    DI,offset stat_fn
  982. stat_2_lp:
  983.     mov    AL,ES:[SI]
  984.     mov    [DI],AL
  985.     inc    SI
  986.     inc    DI
  987.     cmp    AL,null            ;loop till a null byte is found
  988.     jne    stat_2_lp
  989.     mov    byte ptr [DI],cr
  990.     inc    DI
  991.     mov    byte ptr [DI],lf
  992.     inc    DI
  993.     mov    byte ptr [DI],dollar
  994.     display stat_dir        ;display file name
  995. ;
  996. stat_3:
  997.     mov    BX,offset lpt3        ;third printer
  998.     mov    stat_ptr,'3'
  999.     display    stat_lp
  1000.     cmp    ES:[BX].active,on    ;are we active?
  1001.     je    stat_3_a        ;yes
  1002.     display stat_off
  1003.     jmp    short stat_done
  1004. stat_3_a:
  1005.     mov    SI,BX            ;base
  1006.     add    SI,offset filen        ;offset
  1007.     mov    DI,offset stat_fn
  1008. stat_3_lp:
  1009.     mov    AL,ES:[SI]
  1010.     mov    [DI],AL
  1011.     inc    SI
  1012.     inc    DI
  1013.     cmp    AL,null            ;loop till a null byte is found
  1014.     jne    stat_3_lp
  1015.     mov    byte ptr [DI],cr
  1016.     inc    DI
  1017.     mov    byte ptr [DI],lf
  1018.     inc    DI
  1019.     mov    byte ptr [DI],dollar
  1020.     display stat_dir        ;display file name
  1021. ;
  1022. stat_done:
  1023.     ret
  1024. stat    endp
  1025. ;
  1026. cseg    ends
  1027. %out EOF
  1028.     end    lptx
  1029. ;
  1030. ;
  1031. ;
  1032. ;
  1033. ;
  1034. ; Good Luck
  1035. ;
  1036.